A comprehensive, annotated reference to HTML5 and CSS3 — written for developers who already think in code and just need the syntax fast.
Everything covered in this guide
HyperText Markup Language — the skeleton of every webpage
Every HTML5 page follows this exact skeleton. Tags are elements; most have an opening <tag> and closing </tag>. Self-closing tags (<meta>, <img>, <br>) need no closing tag in HTML5.
HTML<!-- HTML comment — ignored by the browser --> <!DOCTYPE html> <!-- NOT a tag. Must be line 1. Tells browser: "Parse this as HTML5." --> <html lang="en"> <!-- Root element wrapping everything. lang= helps screen readers & SEO. --> <head> <!-- Metadata container — nothing here renders. --> <meta charset="UTF-8"> <!-- charset: UTF-8 supports all Unicode characters (emoji, accents…) Always include this as the FIRST child of <head>. --> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- viewport: without this, mobile browsers render at desktop width and then zoom out. Essential for any responsive site. --> <meta name="description" content="My first HTML5 site"> <!-- description: shown in Google search results (max ~155 chars) --> <title>Page Title</title> <!-- Shown in browser tab, bookmarks, and search results. Use a unique, descriptive title per page. --> <link rel="stylesheet" href="style.css"> <!-- Link to external CSS file. rel= relationship type (required — always "stylesheet") href= path to file (relative) or full URL --> </head> <body> <!-- Everything visible goes here. --> <h1>Hello, World!</h1> <!-- <script> at the BOTTOM of body for performance. Browser parses HTML top-to-bottom — a script at the top blocks rendering until it fully downloads. --> <script src="app.js"></script> </body> </html>
Semantic elements describe their purpose, not just appearance. Use them instead of endless <div> tags — they improve SEO, accessibility, and code readability.
| Element | Meaning | Old equivalent |
|---|---|---|
| <header> | Site or section header | <div id="header"> |
| <nav> | Navigation links | <div id="nav"> |
| <main> | Primary page content (once per page) | <div id="main"> |
| <article> | Self-contained piece (post, card) | <div class="post"> |
| <section> | Thematic grouping with a heading | <div class="section"> |
| <aside> | Sidebar / tangentially related content | <div id="sidebar"> |
| <footer> | Page or section footer | <div id="footer"> |
| <figure> | Image + optional caption wrapper | <div class="img-wrap"> |
| <figcaption> | Caption for a <figure> | <p class="caption"> |
| <time> | Machine-readable date/time | <span> |
| <mark> | Highlighted / relevant text | <span class="highlight"> |
| <details> | Native collapsible accordion | (required JS before HTML5) |
| <summary> | Visible label for <details> | (required JS before HTML5) |
<nav>. If it's a standalone blog post → <article>. Visual styling is CSS's job.HTML<!-- ── HEADINGS: h1 (most important) → h6 (least) ───────────── --> <!-- Use ONE <h1> per page. Don't skip levels (h1 → h3). --> <h1>Page Title</h1> <h2>Section</h2> <h3>Sub-section</h3> <!-- h4, h5, h6 continue deeper --> <!-- ── PARAGRAPHS & INLINE FORMATTING ───────────────────────── --> <p> Use <strong>bold importance</strong> and <em>italic emphasis</em>. Subscript: H<sub>2</sub>O Superscript: E=mc<sup>2</sup> Deleted: <del>old price</del> Inserted: <ins>new price</ins> Highlighted: <mark>important</mark> Inline code: <code>console.log()</code> </p> <!-- ── ANCHOR (link) ──────────────────────────────────────────── --> <!-- href= destination URL or path target= _blank = new tab | _self = same tab (default) rel= noopener noreferrer — security MUST for _blank links --> <a href="https://example.com" target="_blank" rel="noopener noreferrer">External</a> <a href="about.html">Relative path</a> <a href="#contact">Jump to #contact anchor on same page</a> <a href="mailto:hi@example.com">Email link</a> <a href="tel:+14045551234">Phone link (mobile tap-to-call)</a> <!-- ── IMAGE ───────────────────────────────────────────────────── --> <!-- src= path/URL to image (REQUIRED) alt= descriptive text for screen readers & broken images Must NOT be empty unless image is purely decorative width/height prevents layout shift while loading --> <img src="photo.jpg" alt="A red barn in a snowy field at dusk" width="800" height="533" loading="lazy"> <!-- loading=lazy defers off-screen images --> <!-- Figure with caption --> <figure> <img src="chart.png" alt="Q4 sales chart"> <figcaption>Fig. 1 — Q4 2024 revenue by region.</figcaption> </figure> <!-- ── STRUCTURAL HELPERS ─────────────────────────────────────── --> <br> <!-- line break — use sparingly, prefer CSS margins --> <hr> <!-- horizontal rule — thematic / topic break --> <span>inline</span> <!-- generic INLINE container (no semantic meaning) --> <div>block</div> <!-- generic BLOCK container (no semantic meaning) --> <!-- ── HTML ENTITIES ─────────────────────────────────────────── --> <!-- Use named or numeric entities for reserved / special chars: --> © <!-- © --> & <!-- & (ampersand inside HTML!) --> < <!-- < (less-than sign inside HTML!) --> > <!-- > --> <!-- non-breaking space --> — <!-- — em dash --> · <!-- · middle dot -->
HTML<!-- ── UNORDERED LIST (bullet points) ───────────────────────── --> <ul> <li>Apples</li> <li>Oranges</li> <li> Basket <!-- lists can be nested inside any <li> --> <ul><li>Grapes</li></ul> </li> </ul> <!-- ── ORDERED LIST (numbered) ──────────────────────────────── --> <!-- type= 1 (default) | A | a | I | i start= starting number | reversed attribute --> <ol type="A" start="3"> <li>Shows as "C"</li> <li>Shows as "D"</li> </ol> <!-- ── DESCRIPTION LIST (term → definition pairs) ───────────── --> <dl> <dt>HTML</dt> <!-- dt = description term --> <dd>HyperText Markup Language</dd> <!-- dd = description detail --> <dt>CSS</dt> <dd>Cascading Style Sheets</dd> </dl> <!-- ── TABLE ─────────────────────────────────────────────────── --> <!-- Use tables for TABULAR DATA, not for page layout. --> <table> <caption>Monthly Sales (USD)</caption> <!-- optional title --> <thead> <!-- thead groups header rows --> <tr> <!-- tr = table row --> <th scope="col">Month</th> <!-- th = header cell --> <th scope="col">Revenue</th> </tr> </thead> <tbody> <!-- tbody groups data rows --> <tr> <td>January</td> <!-- td = data cell --> <td>$12,400</td> </tr> <tr> <td colspan="2">Q1 Total: $38,200</td> <!-- colspan= span multiple columns rowspan= span multiple rows --> </tr> </tbody> <tfoot> <tr><td colspan="2">Year Total: $148,000</td></tr> </tfoot> </table>
Forms send data to a server (action=) using GET (URL params) or POST (hidden body). Every input needs a name= attribute — that becomes the key sent to the server.
HTML<!-- action= where to send form data method= GET (appended to URL) | POST (hidden in request body) --> <form action="/submit" method="POST"> <!-- label: for= MUST match the input's id= — connects them for accessibility. Clicking the label focuses the input. --> <label for="username">Username</label> <input type="text" id="username" <!-- connects to label --> name="username" <!-- key sent to server --> placeholder="jsmith" <!-- hint text; disappears on type --> required <!-- HTML5 built-in validation --> minlength="3" maxlength="30" autocomplete="username"> <!-- HTML5 INPUT TYPES — each has built-in browser validation: --> <input type="email" name="email"> <!-- validates @ format --> <input type="password" name="pass"> <!-- hides characters --> <input type="number" name="age" min="0" max="120" step="1"> <input type="date" name="dob"> <!-- date picker --> <input type="url" name="website"> <input type="tel" name="phone"> <input type="range" name="vol" min="0" max="100"> <!-- slider --> <input type="color" name="fav"> <!-- colour picker --> <input type="file" name="upload" accept="image/*" multiple> <input type="checkbox" name="agree" value="yes" checked> <input type="radio" name="size" value="S"> Small <input type="radio" name="size" value="L"> Large <!-- same name= groups radios; only one can be selected at a time --> <!-- SELECT dropdown --> <select name="country"> <option value="" disabled selected>Choose…</option> <optgroup label="North America"> <!-- group options --> <option value="us">United States</option> <option value="ca">Canada</option> </optgroup> </select> <!-- TEXTAREA: multi-line text. rows/cols set initial size. --> <textarea name="message" rows="5" placeholder="Your message…"></textarea> <!-- FIELDSET groups related inputs; LEGEND labels the group --> <fieldset> <legend>Preferred contact</legend> <input type="radio" name="contact" value="email"> Email <input type="radio" name="contact" value="phone"> Phone </fieldset> <!-- Submit buttons --> <button type="submit">Send</button> <!-- preferred — allows HTML inside --> <input type="reset"> <!-- resets all fields --> </form>
HTML<!-- ── VIDEO ──────────────────────────────────────────────────── --> <!-- controls= show play/pause UI | autoplay start immediately muted= required for autoplay | loop restart when finished poster= thumbnail before play --> <video width="640" controls autoplay muted loop poster="thumb.jpg"> <source src="video.mp4" type="video/mp4"> <!-- browser picks --> <source src="video.webm" type="video/webm"> <!-- first it can play --> Your browser doesn't support HTML5 video. </video> <!-- ── AUDIO ──────────────────────────────────────────────────── --> <audio controls preload="metadata"> <!-- preload= none | metadata | auto --> <source src="track.mp3" type="audio/mpeg"> </audio> <!-- ── CANVAS (draw via JavaScript) ────────────────────────────── --> <canvas id="myCanvas" width="600" height="300">Canvas not supported.</canvas> <!-- ── IFRAME embed ────────────────────────────────────────────── --> <iframe src="https://www.youtube.com/embed/VIDEO_ID" width="560" height="315" title="Video title" <!-- required for accessibility --> allowfullscreen loading="lazy"> </iframe> <!-- ── GLOBAL ATTRIBUTES (work on any element) ─────────────────── --> <div id="hero"> <!-- unique page id for CSS, JS, anchors --> <span class="card active"> <!-- one or more CSS classes --> <p hidden> <!-- display:none equivalent --> <p title="Tooltip text"> <!-- hover tooltip --> <div tabindex="0"> <!-- keyboard focus: 0=natural, -1=JS only --> <p contenteditable="true"> <!-- editable in browser --> <img aria-label="Close menu"> <!-- aria-* for screen readers --> <!-- data-* attributes: embed custom data; read via JS dataset.* --> <button data-product-id="sku-42" data-price="19.99"> Add to Cart </button> <!-- JS access: btn.dataset.productId → "sku-42" btn.dataset.price → "19.99" (dashes in HTML become camelCase in JS) -->
Cascading Style Sheets — the skin, layout & motion of the web
CSS/* CSS comment */ /* Core rule syntax: selector { property: value; } Multiple declarations per rule are allowed. */ h1 { color: #c84b2f; /* hex colour */ font-size: 2rem; /* rem = relative to root font-size (16px) */ margin: 0 0 1rem; /* shorthand: top right bottom left */ }
| Method | Location | Notes |
|---|---|---|
| <link rel="stylesheet" href="s.css"> | In <head> | ✅ Preferred — reusable, cached, clean separation |
| <style> … </style> | In <head> | Good for single-page or critical CSS |
| style="color:red" | On any element | ⚠️ Inline — highest specificity, unmaintainable; avoid |
| @import url("other.css") | Inside CSS file | Loads another file (use <link> in HTML instead) |
CSS/* ── BASIC ────────────────────────────────────────────────────── */ * { } /* universal — every element */ p { } /* element (type) — all <p> */ .card { } /* class — elements with class="card" */ #hero { } /* id — ONE element with id="hero" */ h1, h2, h3 { } /* group — comma = "and also" */ /* ── ATTRIBUTE ────────────────────────────────────────────────── */ a[target="_blank"] { } /* exact attribute value */ input[type="email"] { } /* input of type email */ [href^="https"] { } /* starts with "https" */ [src$=".png"] { } /* ends with ".png" */ [class*="btn"] { } /* contains "btn" */ /* ── COMBINATORS ──────────────────────────────────────────────── */ nav a { } /* DESCENDANT: any <a> inside <nav> */ nav > a { } /* CHILD: only DIRECT <a> children of <nav> */ h2 + p { } /* ADJACENT SIBLING: <p> immediately after <h2> */ h2 ~ p { } /* GENERAL SIBLING: all <p> siblings after <h2> */ /* ── PSEUDO-CLASSES (:) — element STATE ───────────────────────── */ a:hover { } /* cursor over element */ a:focus { } /* has keyboard/click focus */ a:active { } /* being clicked */ a:visited { } /* link previously clicked */ input:disabled { } /* input with disabled attribute */ input:checked { } /* checked checkbox/radio */ input:valid { } /* passes HTML5 validation */ input:invalid { } /* fails HTML5 validation */ p:first-child { } /* <p> that is the first child of its parent */ li:nth-child(2) { } /* 2nd child */ li:nth-child(odd) { } /* 1,3,5… */ li:nth-child(3n+1) { } /* formula: 1,4,7… */ p:not(.special) { } /* every <p> WITHOUT class "special" */ /* ── PSEUDO-ELEMENTS (::) — virtual sub-elements ─────────────── */ p::first-letter { } /* first letter (drop-cap effect) */ ::selection { } /* user-highlighted text */ .card::before { content: "✦ "; /* REQUIRED even if empty string */ color: gold; } /* ::before and ::after inject virtual content INSIDE the element, before or after the actual content. No extra HTML needed. */
When multiple rules target the same element, the cascade decides which wins. The three pillars: Origin, Specificity, Source order.
| Selector type | Score | Example |
|---|---|---|
| Inline style | 1-0-0-0 (highest) | style="color:red" |
| #id | 0-1-0-0 | #hero { } |
| .class / :pseudo / [attr] | 0-0-1-0 | .card:hover { } |
| element / ::pseudo-element | 0-0-0-1 | h1 { } p::before { } |
| !important | Overrides all ⚠️ | Avoid — creates specificity wars |
CSS/* Equal specificity → LATER rule wins (source order): */ p { color: blue; } /* written first */ p { color: red; } /* later → WINS. Text is red. */ /* Higher specificity wins regardless of order: */ p { color: gray; } /* 0-0-0-1 */ .intro { color: teal; } /* 0-0-1-0 beats above */ #hero p.intro { color: navy; } /* 0-1-1-1 beats all above */ /* CSS CUSTOM PROPERTIES (variables) */ :root { --primary: #c84b2f; /* define: prefix -- */ --spacing: 1rem; } .btn { background: var(--primary); /* use with var() */ padding: var(--spacing); color: var(--btn-color, white); /* fallback value if --btn-color unset */ }
Every HTML element is a rectangular box with four layers. With box-sizing: border-box, width/height includes padding and border — no arithmetic surprises.
CSS.box { width: 300px; height: 200px; padding: 16px; /* all 4 sides */ padding: 8px 16px; /* top/bot left/right */ padding: 4px 8px 12px 16px; /* ↑ → ↓ ← */ border: 2px solid #ccc; border-top: 3px dashed red; border-radius: 8px; margin: 0 auto; /* auto centres block */ margin-top: 2rem; box-sizing: border-box; /* ← KEY */ }
*, *::before, *::after { box-sizing: border-box; } to your CSS reset. It's standard practice in every modern project.CSS/* ── DISPLAY ──────────────────────────────────────────────────── */ .item { display: block; /* full width, stacks vertically */ display: inline; /* flows in text; ignores width/height */ display: inline-block; /* flows inline BUT respects w/h */ display: none; /* removed from layout (no space kept) */ visibility: hidden; /* invisible BUT space preserved */ opacity: 0; /* transparent; space kept; animatable! */ } /* ── POSITION ──────────────────────────────────────────────────── */ /* STATIC (default) — in normal flow. top/left/etc have no effect. */ /* RELATIVE — offset from normal position; space preserved. */ .box { position: relative; top: 10px; left: 20px; } /* ABSOLUTE — removed from flow; positioned to nearest non-static ancestor (or <html> as fallback). */ .parent { position: relative; } .badge { position: absolute; top: -8px; right: -8px; /* sticks to top-right of .parent */ } /* FIXED — relative to VIEWPORT; stays during scroll. */ nav { position: fixed; top: 0; left: 0; right: 0; z-index: 100; /* stack order; higher = on top */ } /* STICKY — relative until scroll threshold, then fixed. */ .header { position: sticky; top: 60px; /* sticks 60px from viewport top */ } /* Perfect centring trick with absolute: */ .centered { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); /* pull back by own 50% */ }
Flexbox arranges items along a single axis (row or column). The parent is the flex container; its direct children are flex items.
CSS/* ── CONTAINER properties ────────────────────────────────────── */ .parent { display: flex; /* activates Flexbox */ flex-direction: row; /* row | row-reverse | column | column-reverse */ justify-content: space-between; /* MAIN axis: flex-start | center | flex-end | space-between | space-around | space-evenly */ align-items: center; /* CROSS axis: stretch | flex-start | flex-end | center */ flex-wrap: wrap; /* nowrap (default) | wrap | wrap-reverse */ gap: 1rem; /* space between items */ } /* ── ITEM properties ─────────────────────────────────────────── */ .item { /* flex: grow shrink basis */ flex: 1 1 200px; /* grow=1, shrink=1, starting size=200px */ flex: 1; /* grow=1, shrink=1, basis=0 (equal share) */ flex: none; /* don't grow or shrink */ align-self: flex-end; /* override align-items for this one item */ order: -1; /* reorder visually without changing HTML */ }
Grid places items on rows and columns simultaneously — best for full page layouts.
CSS/* ── CONTAINER ──────────────────────────────────────────────── */ .layout { display: grid; grid-template-columns: repeat(3, 1fr); /* 3 equal columns */ grid-template-columns: 200px 1fr 2fr; /* mixed units */ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); /* responsive auto columns */ gap: 1.5rem; /* row + column gap */ } /* ── NAMED TEMPLATE AREAS ────────────────────────────────────── */ .page { display: grid; grid-template-columns: 250px 1fr; grid-template-rows: auto 1fr auto; grid-template-areas: "header header" "sidebar content" "footer footer"; } header { grid-area: header; } aside { grid-area: sidebar; } main { grid-area: content; } footer { grid-area: footer; } /* ── ITEM PLACEMENT ─────────────────────────────────────────── */ .banner { grid-column: 1 / -1; /* line 1 to last line (full width) */ grid-column: span 2; /* span 2 columns from current position */ grid-row: 1 / 3; /* row lines 1 to 3 */ }
CSS/* ── COLOR FORMATS ──────────────────────────────────────────── */ color: tomato; /* 148 CSS named colours */ color: #c84b2f; /* hex #rrggbb */ color: #c84; /* shorthand #rgb */ color: rgb(200, 75, 47); /* RGB 0–255 each */ color: rgba(200, 75, 47, 0.5); /* RGBA — a = alpha (0 transparent, 1 opaque) */ color: hsl(12, 62%, 48%); /* HSL — Hue° Saturation% Lightness% */ color: hsl(12 62% 48% / 0.7); /* modern syntax with alpha */ /* ── BACKGROUNDS ─────────────────────────────────────────────── */ .box { background-color: white; background-image: url('photo.jpg'); background-size: cover; /* cover | contain | 100% | 300px */ background-position: center; background-repeat: no-repeat; /* Gradients */ background: linear-gradient(135deg, #c84b2f 0%, #e8a844 100%); background: radial-gradient(circle at top, #fff 0%, #ccc 100%); } /* ── TYPOGRAPHY ──────────────────────────────────────────────── */ body { font-family: 'Georgia', serif; /* stack: browser tries left-to-right */ font-size: 1rem; /* 1rem = 16px (root default) */ font-weight: 400; /* 100=Thin 400=Normal 700=Bold 900=Black */ font-style: normal; /* normal | italic */ line-height: 1.6; /* unitless ✅ — scales with font-size */ letter-spacing: .04em; /* em = relative to current font-size */ text-align: left; /* left | right | center | justify */ text-transform: uppercase; /* uppercase | lowercase | capitalize */ text-decoration:underline; /* underline | line-through | none */ } /* clamp(min, preferred, max) — fluid sizing without media queries */ h1 { font-size: clamp(1.8rem, 5vw, 4rem); } .container { padding: clamp(1rem, 3vw, 3rem); } /* ── SHADOWS ─────────────────────────────────────────────────── */ .card { /* box-shadow: h-offset v-offset blur spread colour */ box-shadow: 0 4px 20px rgba(0,0,0,.12); box-shadow: 0 1px 3px rgba(0,0,0,.1), /* stacked shadows */ 0 8px 32px rgba(0,0,0,.08); }
CSS/* ── TRANSFORMS — move/rotate/scale without affecting layout ─── */ .item { transform: translateX(50px) /* move right */ translateY(-20px) /* move up */ rotate(45deg) /* rotate clockwise */ scale(1.5) /* scale X and Y equally */ skewX(10deg); /* slant on X axis */ transform-origin: top left; /* pivot point (default: center) */ } /* ── TRANSITIONS — smooth change between two states ──────────── */ .btn { background: navy; /* transition: property duration timing-function delay */ transition: background .3s ease, transform .2s ease; /* timing functions: ease | linear | ease-in | ease-out | ease-in-out | cubic-bezier(x1,y1,x2,y2) */ } .btn:hover { background: dodgerblue; transform: scale(1.05); /* transition fires from here */ } /* ── @KEYFRAMES — full independent motion ─────────────────────── */ /* Step 1: define the animation */ @keyframes bounce { 0% { transform: translateY(0); } 50% { transform: translateY(-30px); } 100% { transform: translateY(0); } } @keyframes fade-in { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } /* Step 2: apply to element */ .animated { /* animation: name duration timing delay iteration direction fill-mode */ animation: bounce 1.2s ease-in-out 0s infinite normal both; /* fill-mode: both = stays at last frame AND applies before start */ animation-play-state: paused; /* pause/play via JS class toggle */ } /* Multiple staggered animations via animation-delay: */ .card:nth-child(1) { animation-delay: .1s; } .card:nth-child(2) { animation-delay: .25s; } .card:nth-child(3) { animation-delay: .4s; }
Mobile-first approach: write base styles for small screens, then add overrides for larger ones with min-width.
CSS/* ── MOBILE-FIRST (recommended) ─────────────────────────────── */ /* Base: applies to ALL screen sizes */ .grid { display: grid; grid-template-columns: 1fr; /* single column on mobile */ } /* min-width = "at least this wide" */ @media (min-width: 640px) { /* tablet+ */ .grid { grid-template-columns: repeat(2, 1fr); } } @media (min-width: 1024px) { /* desktop+ */ .grid { grid-template-columns: repeat(3, 1fr); } } /* ── OTHER MEDIA FEATURES ────────────────────────────────────── */ @media (prefers-color-scheme: dark) { /* OS dark mode */ body { background: #111; color: white; } } @media (prefers-reduced-motion: reduce) { /* accessibility */ * { animation-duration: .01ms !important; } } @media (orientation: landscape) { } @media print { } /* print stylesheet */ @media (hover: none) { } /* touch devices (no mouse hover) */ /* ── COMBINING CONDITIONS ───────────────────────────────────── */ @media (min-width: 640px) and (max-width: 1023px) { /* tablet range ONLY */ }
A complete, annotated beginner website — pure HTML + CSS, no server needed
A beginner HTML5 + CSS website — annotated & responsive
This site demonstrates HTML5 semantics, CSS Grid, Flexbox, forms, and responsive design in a single annotated file.
What is the web made of? Every webpage is built from HTML (structure), CSS (style), and optionally JavaScript (behaviour). The browser downloads these files and renders them into the visual page you see.
Understanding this pipeline — from text files to pixels — is the foundation of web development.
Copy everything below into index.html. Open it. Modify it. Break it. Fix it. That's how you learn.
HTML + CSS<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content="My first HTML5 website"> <title>Hello World</title> <!-- Google Fonts (optional) --> <link rel="preconnect" href="https://fonts.googleapis.com"> <link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700&family=Source+Serif+4:wght@400;600&display=swap" rel="stylesheet"> <style> /* ════════════════════════════════════════════════ CSS CUSTOM PROPERTIES ════════════════════════════════════════════════ */ :root { --bg: #faf6ef; --ink: #1c1410; --muted: #7a6555; --accent: #c84b2f; --teal: #1e6b6b; --border: #cdbfa8; --font-head: 'Playfair Display', Georgia, serif; --font-body: 'Source Serif 4', Georgia, serif; } /* ════════════════════════════════════════════════ RESET ════════════════════════════════════════════════ */ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } html { scroll-behavior: smooth; } /* ════════════════════════════════════════════════ BASE BODY ════════════════════════════════════════════════ */ body { font-family: var(--font-body); background: var(--bg); color: var(--ink); line-height: 1.7; } /* ════════════════════════════════════════════════ REUSABLE CONTAINER ════════════════════════════════════════════════ */ .container { max-width: 900px; margin: 0 auto; /* auto = centres block element */ padding: 0 1.5rem; } /* ════════════════════════════════════════════════ TYPOGRAPHY ════════════════════════════════════════════════ */ h1, h2, h3 { font-family: var(--font-head); line-height: 1.2; } h1 { font-size: clamp(2rem, 5vw, 3.5rem); } h2 { font-size: 1.4rem; margin-bottom: .75rem; } p { margin-bottom: 1rem; color: #3d2f24; } a { color: var(--teal); text-decoration: underline; } a:hover { color: var(--accent); } /* ════════════════════════════════════════════════ STICKY NAVIGATION position: sticky stays visible during scroll ════════════════════════════════════════════════ */ .site-nav { position: sticky; top: 0; z-index: 50; background: #1c1410; padding: .7rem 0; } .nav-inner { display: flex; /* Flexbox for horizontal nav */ align-items: center; justify-content: space-between; max-width: 900px; margin: 0 auto; padding: 0 1.5rem; } .nav-logo { font-family: var(--font-head); color: #faf6ef; font-size: 1.2rem; text-decoration: none; } .nav-links { list-style: none; /* remove default bullet points */ display: flex; gap: 1.5rem; } .nav-links a { color: #b0a090; text-decoration: none; font-size: .9rem; transition: color .2s; /* smooth colour on hover */ } .nav-links a:hover { color: white; } /* ════════════════════════════════════════════════ HERO SECTION ════════════════════════════════════════════════ */ .hero { min-height: 60vh; /* at least 60% of viewport height */ display: flex; flex-direction: column; justify-content:center; padding: 5rem 0; background: linear-gradient(135deg,#1c1410 0%,#3d2f24 100%); color: white; } .hero h1 { color: white; margin-bottom: 1rem; } .hero p { color: #b0a090; max-width: 500px; } .hero-tag { display: inline-block; background: rgba(200,75,47,.25); border: 1px solid rgba(200,75,47,.5); border-radius:100px; padding: .3em .9em; font-size: .75rem; color: #e8a080; margin-bottom:1rem; } /* ════════════════════════════════════════════════ PAGE LOAD ANIMATION (staggered reveal) ════════════════════════════════════════════════ */ @keyframes reveal { from { opacity:0; transform:translateY(24px); } to { opacity:1; transform:translateY(0); } } .reveal { animation: reveal .7s ease both; } .delay-1 { animation-delay: .15s; } .delay-2 { animation-delay: .3s; } /* ════════════════════════════════════════════════ CSS GRID PAGE LAYOUT (2 columns) ════════════════════════════════════════════════ */ .main-grid { display: grid; grid-template-columns: 2fr 1fr; /* main 2/3 + sidebar 1/3 */ gap: 2rem; padding: 3rem 0; } .card { background: white; border-radius: 12px; padding: 1.75rem 2rem; box-shadow: 0 2px 20px rgba(0,0,0,.08); border: 1px solid #e5dac8; margin-bottom: 1.5rem; } /* ════════════════════════════════════════════════ ARTICLE METADATA ════════════════════════════════════════════════ */ .post-meta { font-size: .82rem; color: var(--muted); margin-bottom:1rem; } /* ════════════════════════════════════════════════ SIDEBAR SKILL TAGS (hover transition) ════════════════════════════════════════════════ */ .sidebar-tag { display: inline-block; background: #f0e9db; border-radius:100px; padding: .2em .75em; font-size: .8rem; margin: .2rem; transition: background .2s; } .sidebar-tag:hover { background: var(--accent); color: white; } /* ════════════════════════════════════════════════ FORM STYLES ════════════════════════════════════════════════ */ label { display: block; font-size: .85rem; font-weight: 600; color: var(--muted); margin-top: .9rem; margin-bottom: .3rem; } input[type="text"], input[type="email"], select, textarea { width: 100%; padding: .55rem .9rem; border: 1.5px solid var(--border); border-radius:6px; font-family: var(--font-body); font-size: .95rem; outline: none; transition: border-color .2s; } input:focus, select:focus, textarea:focus { border-color: var(--teal); box-shadow: 0 0 0 3px rgba(30,107,107,.15); } textarea { min-height: 100px; resize: vertical; } .btn { margin-top: 1.25rem; background: var(--accent); color: white; border: none; border-radius:6px; padding: .65rem 1.75rem; font-family: var(--font-body); font-weight: 600; cursor: pointer; transition: background .2s, transform .15s; } .btn:hover { background: #a83a22; transform: translateY(-1px); } .btn:active { transform: translateY(0); } /* ════════════════════════════════════════════════ FOOTER ════════════════════════════════════════════════ */ .site-footer { background: #1c1410; color: #7a6555; padding: 2.5rem 0; text-align: center; font-size: .88rem; } /* ════════════════════════════════════════════════ RESPONSIVE — single column on mobile ════════════════════════════════════════════════ */ @media (max-width: 640px) { .main-grid { grid-template-columns: 1fr; } } </style> </head> <body> <!-- ───────────────────────────────────────────────────────── NAVIGATION <nav> — sticky header, Flexbox layout ───────────────────────────────────────────────────────────── --> <nav class="site-nav" aria-label="Main navigation"> <div class="nav-inner"> <a href="#" class="nav-logo">Hello World</a> <!-- <ul> unordered list | <li> list item | <a> link --> <ul class="nav-links"> <li><a href="#">Home</a></li> <li><a href="#about">About</a></li> <li><a href="#blog">Blog</a></li> <li><a href="#contact">Contact</a></li> </ul> </div> </nav> <!-- ───────────────────────────────────────────────────────── HERO <section> — gradient bg, staggered animation ───────────────────────────────────────────────────────────── --> <section class="hero"> <div class="container"> <!-- .reveal and .delay-* classes trigger CSS @keyframes on load --> <span class="hero-tag reveal">HTML5 + CSS3</span> <h1 class="reveal delay-1">Hello, World!</h1> <p class="reveal delay-2"> A complete beginner website: semantic HTML5, CSS Grid layout, Flexbox nav, forms, transitions, and responsive media queries — all in a single annotated file. </p> </div> </section> <!-- ───────────────────────────────────────────────────────── MAIN CONTENT <main> ───────────────────────────────────────────────────────────── --> <main> <div class="container"> <div class="main-grid"> <!-- LEFT: Article + Form ─────────────────────────────────── --> <div> <!-- <article> = self-contained piece of content --> <article class="card" id="blog"> <header> <!-- <time datetime=> is machine-readable for search engines --> <p class="post-meta"> <time datetime="2025-01-15">January 15, 2025</time> · 5 min read </p> <h2>What is the web made of?</h2> </header> <p> Every webpage is built from: <strong>HTML</strong> (structure), <strong>CSS</strong> (style), and <strong>JavaScript</strong> (behaviour). </p> <!-- Ordered list --> <ol> <li>Browser requests the HTML file from a server</li> <li>Browser parses HTML and builds the DOM tree</li> <li>CSS is applied to style the DOM elements</li> <li>Browser paints the result to screen</li> </ol> <!-- <figure> / <figcaption> --> <figure style="margin:1.5rem 0;background:#f5f0e8; border-radius:8px;padding:1.5rem;text-align:center"> <p style="font-size:2rem;margin:0">🌐 → 📄 → 🎨 → 🖥️</p> <figcaption style="font-size:.82rem;color:#7a6555;margin-top:.5rem"> Fig. 1 — How a browser renders a webpage </figcaption> </figure> <!-- <details> / <summary> = native accordion, no JS needed --> <details style="margin-top:1rem;border:1px solid #e5dac8; border-radius:8px;padding:.75rem 1rem"> <summary style="cursor:pointer;font-weight:600"> Did you know? Click to expand </summary> <p style="margin-top:.75rem"> The first website ever created is still online at <a href="http://info.cern.ch" target="_blank" rel="noopener">info.cern.ch</a>. Tim Berners-Lee created it in 1991. </p> </details> </article> <!-- CONTACT FORM <section> + <form> ───────────────────────── --> <section class="card" id="contact"> <h2>Contact Me</h2> <form action="" method="POST"> <!-- Two columns via inline Grid --> <div style="display:grid;grid-template-columns:1fr 1fr;gap:1rem"> <div> <label for="fname">First Name</label> <input type="text" id="fname" name="fname" required placeholder="Jane"> </div> <div> <label for="lname">Last Name</label> <input type="text" id="lname" name="lname" placeholder="Smith"> </div> </div> <label for="email">Email Address</label> <input type="email" id="email" name="email" required placeholder="jane@example.com"> <label for="subject">Subject</label> <select id="subject" name="subject"> <option value="">Choose…</option> <option value="hi">Just saying hi</option> <option value="work">Work enquiry</option> <option value="other">Other</option> </select> <label for="message">Message</label> <textarea id="message" name="message" rows="4" placeholder="Write your message here…"></textarea> <!-- Checkbox --> <div style="display:flex;align-items:center;gap:.5rem;margin-top:1rem"> <input type="checkbox" id="subscribe" name="subscribe" value="yes"> <label for="subscribe" style="margin:0;font-weight:400"> Subscribe to newsletter </label> </div> <!-- <button type="submit"> submits the form --> <button type="submit" class="btn">Send Message →</button> </form> </section> </div><!-- /left column --> <!-- RIGHT: Sidebar <aside> ─────────────────────────────────── --> <aside id="about"> <div class="card"> <h2>About</h2> <!-- <figure> wraps visual content --> <figure style="text-align:center;margin-bottom:1rem"> <div style="width:80px;height:80px;border-radius:50%; background:#f0e9db;display:flex;align-items:center; justify-content:center;font-size:2.5rem;margin:0 auto"> 👋 </div> </figure> <p>Learning HTML5 + CSS3 by building this site from scratch. All in one annotated file.</p> <!-- Unordered list with no bullets (styled via CSS) --> <ul style="list-style:none;padding:0"> <li>📍 Sugar Hill, GA</li> <li>💻 HTML + CSS learner</li> <li>📚 Always reading docs</li> </ul> </div> <div class="card"> <h2>Skills</h2> <!-- <span> inline elements styled as pill tags --> <span class="sidebar-tag">HTML5</span> <span class="sidebar-tag">CSS3</span> <span class="sidebar-tag">Flexbox</span> <span class="sidebar-tag">CSS Grid</span> <span class="sidebar-tag">Forms</span> <span class="sidebar-tag">Animations</span> </div> <div class="card"> <h2>Next Steps</h2> <!-- <dl> description list: <dt> term, <dd> detail --> <dl style="font-size:.88rem"> <dt style="font-weight:600;margin-top:.5rem">JavaScript</dt> <dd style="color:#7a6555;margin-left:1rem">DOM, events, fetch API</dd> <dt style="font-weight:600;margin-top:.5rem">Frameworks</dt> <dd style="color:#7a6555;margin-left:1rem">React, Vue, Svelte</dd> <dt style="font-weight:600;margin-top:.5rem">Back-end</dt> <dd style="color:#7a6555;margin-left:1rem">Node.js, PHP, Python</dd> </dl> </div> </aside> </div><!-- /main-grid --> </div><!-- /container --> </main> <!-- ───────────────────────────────────────────────────────── FOOTER <footer> ───────────────────────────────────────────────────────────── --> <footer class="site-footer"> <div class="container"> <!-- HTML entities: © → © (copyright) · → · (middle dot) & → & (literal ampersand in HTML) --> <p>© <time datetime="2025">2025</time> Hello World Site · Built with HTML5 & CSS3 </p> <nav aria-label="Footer navigation" style="margin-top:.75rem"> <a href="#" style="color:#b0a090;margin:0 .75rem">Home</a> <a href="#about" style="color:#b0a090;margin:0 .75rem">About</a> <a href="#contact" style="color:#b0a090;margin:0 .75rem">Contact</a> </nav> </div> </footer> </body> </html>